package org.streets.eis.ext.rbac.pages;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.wicket.Component;
import org.apache.wicket.Page;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow.PageCreator;
import org.apache.wicket.extensions.markup.html.tabs.ITab;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.link.AbstractLink;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.util.string.Strings;
import org.streets.commons.util.GUID;
import org.streets.database.ExecMode;
import org.streets.database.Limits;
import org.streets.database.SQLBatcher;
import org.streets.database.SQLConnection;
import org.streets.eis.component.dropdown.ToolBar;
import org.streets.eis.component.grid.DefualtNavigatorLabel;
import org.streets.eis.component.grid.EditFlagColumn;
import org.streets.eis.component.grid.EditableColumn;
import org.streets.eis.component.grid.TableList;
import org.streets.eis.component.grid.TableList.ExcelFile;
import org.streets.eis.component.messagebox.MessageBox;
import org.streets.eis.component.messagebox.MessageBox.ReturnType;
import org.streets.eis.component.model.DataModel;
import org.streets.eis.component.model.DefaultTableModel;
import org.streets.eis.component.model.MenuItem;
import org.streets.eis.component.tabs.Tab;
import org.streets.eis.component.tabs.TabsPanel;
import org.streets.eis.entity.Organization;
import org.streets.eis.entity.Role;
import org.streets.eis.ext.rbac.services.RBACAuthorizer;
import org.streets.eis.pages.BasePage;
import org.streets.eis.setting.validatior.TableListValidator;
import org.streets.eis.types.PermitTarget;
import org.streets.eis.types.UnitType;

import com.inmethod.grid.IGridColumn;
import com.inmethod.grid.column.CheckBoxColumn;

public class RoleListPage extends BasePage {
	@Inject
	private SQLConnection connection;
	
	@Inject
	private RBACAuthorizer authorizer;
	
	private TableList<Role> roleList;
	
	private ModalWindow childWindow; 
	
	private String roleSql = "SELECT * FROM EIS_ROLES WHERE ORGAN_ID='%s' ";
	
	private String sql;
	
	private String organId;
	
	private FeedbackPanel feedbackPanel; 
	
	private TabsPanel permsTab;
	
	@SuppressWarnings("unchecked")
	public RoleListPage(final String organId){
		super();
		
		roleSql = String.format(roleSql,organId);
		this.organId = organId;
		
		add(new Label("htmlTitle","角色列表"));
		
		add(childWindow = new ModalWindow("childWindow"));
		childWindow.setOutputMarkupId(true);
		
		feedbackPanel = new FeedbackPanel("feedback");	
		
		Form form = new Form("form"){
			private static final long serialVersionUID = 1L;
			protected void onError(){
				roleList.onValidateError(feedbackPanel);
			}
		};
		
		add(form);
		
		form.add(feedbackPanel.setOutputMarkupId(true));
		form.add(roleList=createRoleList("roleList"));
		roleList.setAllowSelectMultiple(false);	
		roleList.setClickRowToSelect(true);
		roleList.setShowFilterBar(true);
		
		form.add(permsTab = createPermissionTabs(null));
		permsTab.setOutputMarkupId(true);

		form.add(createToolBar());
    }
	
	private ToolBar createToolBar(){
		DataModel<MenuItem> model = new DataModel<MenuItem>();
		model.addChild(new DataModel<MenuItem>(new MenuItem("insert","insert","新增角色")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("copy","copy","从上级公司复制角色")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("post","post","保存修改")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("refresh","refresh","&nbsp;刷新&nbsp;")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("delete","delete","&nbsp;删除&nbsp;")));
		model.addChild(new DataModel<MenuItem>(new MenuItem("saveAs","saveAs","导出角色列表")));
		
		return new ToolBar("toolbar",model){
			private static final long serialVersionUID = 1L;
			@Override
			protected boolean needFormSubmitted(MenuItem menuItem){
				return "post".equals(menuItem.getCode());
			}
			@Override
			protected void onMenuItemClicked(AbstractLink link,DataModel<MenuItem> dataModel,AjaxRequestTarget target){
				if ("insert".equals(dataModel.getObject().getCode())){
        			insert(target);
        		}
				if ("copy".equals(dataModel.getObject().getCode())){
        			copyRole(target);
        		}
				if ("delete".equals(dataModel.getObject().getCode())){
        			deleteSelected(target);
        		}
				if ("post".equals(dataModel.getObject().getCode())){
        			postIt(target);
        		}
				if ("refresh".equals(dataModel.getObject().getCode())){
					roleList.cancelEditAllRows();
					roleList.resetSelectedItems();
					target.addComponent(getPage());
        		}
				if ("saveAs".equals(dataModel.getObject().getCode())){
					saveAsExcel(target);
        		}				
        	}
        };
	}
	
	private TabsPanel createPermissionTabs(final Role role){
		List<ITab> perms = new ArrayList<ITab>();
		perms.add(new Tab(PermitTarget.ORGAN.getName(),"机构权限",OrganPermissionPanel.class){
			private static final long serialVersionUID = 1L;
			@Override
			public Panel getPanel(String panelId) {
				return new OrganPermissionPanel(panelId,role);
			}
		});
		perms.add(new Tab(PermitTarget.FUNC.getName(),"功能权限",FuncPermissionPanel.class){
			private static final long serialVersionUID = 1L;
			@Override
			public Panel getPanel(String panelId) {
				return new FuncPermissionPanel(panelId,role);
			}
		});
		perms.add(new Tab(PermitTarget.FIELD.getName(),"字段权限",FieldPermissionPanel.class){
			private static final long serialVersionUID = 1L;
			@Override
			public Panel getPanel(String panelId) {
				return new FieldPermissionPanel(panelId,role);
			}
		});

		TabsPanel panel =  new TabsPanel("permsTab",perms);
		if (permsTab!=null){
			panel.setSelectedTab(permsTab.getSelectedTab());
		}
		return panel;
	}
	
	private TableList<Role> createRoleList(String id){
		return new TableList<Role>(id, new DefaultTableModel<Role>(){
			private static final long serialVersionUID = 1L;
			@Override
			public List<Role> getPageRecords(long offset,int limit,String sortProperty,boolean isAsc){
				String orderBy = (!Strings.isEmpty(sortProperty)) ? " ORDER BY " + sortProperty +(isAsc? " ASC" : " DESC") : "";
				StringBuffer where = new StringBuffer(" and (1=1 ");
				for (String filterSql : roleList.getFilterSqls().values()){
					where.append(" and ").append(filterSql);
				}
				where.append(")");
				sql = roleSql + where.toString() + orderBy;
				return connection.query(sql , Role.class,Limits.none());
			}
			@Override
			protected  long getRecordsCount(){
				return connection.count(sql);
			}
		}, generateRoleColumns()){
			private static final long serialVersionUID = 1L;
			@Override
			protected Role reloadRowObject(final Role curValue){
				return connection.unique(roleSql + " AND ID=?",Role.class,new String[]{curValue.getId()});
			}
			@Override
			protected Component newNavigationLabel(String id) {
				return new DefualtNavigatorLabel(id,this);
			}
			@Override
			protected Component newPagingNavigator(String id) {
				return new WebMarkupContainer(id);
			}
			@SuppressWarnings("unchecked")
			@Override
			public void onItemSelectionChanged(IModel item, boolean newValue) {
				super.onItemSelectionChanged(item, newValue);
				if (newValue){					
					if (roleList.getSelectedItems().size()==1){
						Role role = (Role) item.getObject();
						TabsPanel tmp = createPermissionTabs(role);
						tmp.setOutputMarkupId(true);
						permsTab.replaceWith(tmp);
						permsTab = tmp;
						AjaxRequestTarget.get().addComponent(permsTab);
					}
				}				
			}
		}.add(new TableListValidator<Role>("unique.role.code","name") {
			private static final long serialVersionUID = 1L;
			@Override
			public boolean doValidate(FormComponent<?>[] formComponents,Role object) {
				return connection.count("SELECT * FROM EIS_ROLES WHERE NAME=? AND ORGAN_ID=? AND ID<>?",new Object[]{formComponents[0].getInput(),organId,object.getId()}) == 0;
			}
			@Override
			public boolean doValidate(Map<Role, FormComponent<?>[]> editedRows) {
				List<String> tmp = new ArrayList<String>(editedRows.size());
				for (FormComponent<?>[] formComponents : editedRows.values()){
					String key = formComponents[0].getInput();
					if (tmp.contains(key)){
						return false;
					} else {
						tmp.add(key);
					}
				}
				return true;
			}
		}).add(new TableListValidator<Role>("unique.role.code","code") {
			private static final long serialVersionUID = 1L;
			@Override
			public boolean doValidate(FormComponent<?>[] formComponents,Role object) {
				return connection.count("SELECT * FROM EIS_ROLES WHERE CODE=? AND ORGAN_ID=? AND ID<>?",new Object[]{formComponents[0].getInput(),organId,object.getId()}) == 0;
			}
			@Override
			public boolean doValidate(Map<Role, FormComponent<?>[]> editedRows) {
				List<String> tmp = new ArrayList<String>(editedRows.size());
				for (FormComponent<?>[] formComponents : editedRows.values()){
					String key = formComponents[0].getInput();
					if (tmp.contains(key)){
						return false;
					} else {
						tmp.add(key);
					}
				}
				return true;
			}
		});
	}
	
	private List<IGridColumn> generateRoleColumns(){
		List<IGridColumn> columns = new ArrayList<IGridColumn>();
		columns.add(new CheckBoxColumn("check"));
		columns.add(new EditFlagColumn("editFlag"));
		columns.add(new EditableColumn(Model.of("角色标识"), "code", "CODE") {
			private static final long serialVersionUID = 1L;
			
			@SuppressWarnings("unchecked")
			@Override
			protected void addValidators(FormComponent component) {
				component.setRequired(true);
			}
		}.setInitialSize(85));
		columns.add(new EditableColumn(Model.of("角色名称"), "name", "NAME") {
			private static final long serialVersionUID = 1L;
			
			@SuppressWarnings("unchecked")
			@Override
			protected void addValidators(FormComponent component) {
				component.setRequired(true);
			}
		}.setInitialSize(130));
		columns.add(new EditableColumn(Model.of("角色值"), "value", "VALUE") {
			private static final long serialVersionUID = 1L;
			
			@SuppressWarnings("unchecked")
			@Override
			protected void addValidators(FormComponent component) {
				component.setRequired(true);
			}
		}.setInitialSize(60));
		
		return columns;
	}
	
	private void insert(AjaxRequestTarget target){
		childWindow.setPageCreator(new PageCreator(){
			private static final long serialVersionUID = 1L;
			public Page createPage() {
				return new RoleInsertPage(childWindow,organId);
			}			
		});
		childWindow.setTitle("新增角色");
		childWindow.setWindowClosedCallback(new ModalWindow.WindowClosedCallback(){
			private static final long serialVersionUID = 1L;
			public void onClose(AjaxRequestTarget target){
				target.addComponent(getPage());
			}
		});

		childWindow.setMinimalWidth(500);
		childWindow.setMinimalHeight(400);
		childWindow.setInitialWidth(500);
		childWindow.setInitialHeight(400);		
		childWindow.show(target);
	}
	
	private void copyRole(AjaxRequestTarget target){
		Organization org = connection.unique(Organization.class, organId);
		if (connection.count(String.format("SELECT * FROM EIS_ROLES WHERE ORGAN_ID='%s'",org.getId()))>0){
			getMessageBox().warning("此机构下已经存在角色。不能从上级公司再复制职位！");
			return;
		}
		Organization tmp = org;
		while((tmp=connection.unique(Organization.class, tmp.getParentId()))!=null){
			if (tmp.getAttr().equals(String.valueOf(UnitType.GROUP.value()))||
					tmp.getAttr().equals(String.valueOf(UnitType.COMPANY.value()))){
				String sourceSql = String.format("SELECT * FROM EIS_ROLES WHERE ORGAN_ID='%s'",tmp.getId());
				List<Role> source = connection.query(sourceSql , Role.class, Limits.none());
				
				if (source.size()>0){					
					String destSql = "INSERT INTO EIS_ROLES(ID,CODE,NAME,VALUE,ORGAN_ID) VALUES(?,?,?,?,?)";
					SQLBatcher batcher = connection.prepare(destSql);	
					for(Role role : source){
						batcher.add(new Object[]{
								GUID.nextUUID(),
								role.getCode(),
								role.getName(),
								role.getValue(),
								organId
						});
					}					
					batcher.execute();
					getMessageBox().alert("从"+tmp.getName()+"成功复制了"+source.size()+"条角色记录！",new MessageBox.DialogCallback(){
						private static final long serialVersionUID = 1L;

						public void onDialogClosed(AjaxRequestTarget target,ReturnType result) {
							target.addComponent(getPage());
						}
					});
					return;
				}
			}
		}
		getMessageBox().error("所有上级公司均没有角色信息。无法完成复制！");
	}
	
	@SuppressWarnings("unchecked")
	private void deleteSelected(AjaxRequestTarget target){
		if (roleList.getSelectedItems().size()>0){
			getMessageBox().question("确定要删除"+roleList.getSelectedItems().size()+"条记录吗？",new MessageBox.DialogCallback(){
				private static final long serialVersionUID = 1L;

				public void onDialogClosed(AjaxRequestTarget target,ReturnType result) {
					if (result == ReturnType.YES){						
						StringBuffer sqls = new StringBuffer();
						List<Role> roles = new ArrayList<Role>();
						for (Iterator iterator = roleList.getSelectedItems().iterator(); iterator.hasNext();) {
							IModel rowModel = (IModel) iterator.next();
							//删除前一定要先将所选行设为未选
							roleList.selectItem(rowModel,false);
							Role role = (Role) (rowModel).getObject();
							roles.add(role);
							
							sqls.append(String.format("DELETE FROM EIS_POS_ROLE_MAP WHERE ROLE_ID='%s';DELETE FROM EIS_ROLES WHERE ID='%s';",role.getId(), role.getId()));
						}
						//
						if (authorizer.removeRolePermissions(roles.toArray(new Role[0]))) {
							connection.execute(sqls.toString());						
						}
						target.addComponent(getPage());
					}
				}
				
			});			
		} else {
			getMessageBox().error("请选择要删除的记录!");
		}
	}
	
	private void postIt(AjaxRequestTarget target){
		List<IModel<Role>> editedList = roleList.getEditingRowModels();		
		if (editedList.size()>0){
			for (Iterator<IModel<Role>> iterator = editedList.iterator(); iterator.hasNext();) {
				IModel<Role> rowModel = iterator.next();
				connection.execute(rowModel.getObject(), ExecMode.UPDATE);
				roleList.setItemEdit(rowModel, false);
			}
			target.addComponent(feedbackPanel);
			roleList.update();
		}
	}	
	
	private void saveAsExcel(AjaxRequestTarget target){
		roleList.setCreateExcelCallback(new TableList.CreateExcelFileCallback(){
			private static final long serialVersionUID = 1L;
			public ExcelFile createExcel() {
				String fileName = String.format("角色列表-%s.xls",new SimpleDateFormat("yyyyMMdd").format(new Date()));
				return roleList.generateExcelFile(fileName,"角色列表",connection.query(sql , Role.class,Limits.none()),roleList.getAllColumns());
			}
		});	
		target.appendJavascript(roleList.getSaveAsExcelJavascript());
	}	
}
